/**
 * 菜单处理模块
 */
const { validationResult } = require('express-validator');
const { httpStatusCode } = require('@root/types/HttpStatusCode.js');
const { poolPromise } = require('@root/db/index');
const { validateParams } = require('@root/utils/peak-tools.js');
const config = require('@root/config/index');

/**
 * 转换路由参数
 */
function convertRouteParameter(route) {
  return {
    parent_id: route.parent_id,
    menu_id: route.menu_id,
    name: route.route_name,
    path: route.path,
    component: route.component,
    meta: {
      title: route.menu_name,
      icon: route.icon,
      activeMenu: route.active_menu,
      target: route.target,
      isLink: !!route.is_link,
      isKeepAlive: !!route.is_keep_alive,
      isHidden: !!route.is_hidden,
      isRefresh: !!route.is_refresh,
      isAffix: !!route.is_affix,
      isFull: !!route.is_full,
      isAlwaysShow: !!route.is_always_show,
    },
  };
}

/**
 * 转换嵌套树结构
 * @param {*} list
 */
function treeMenu(list, isRoute = false) {
  const result = [];
  const map = new Map();
  list.forEach((item) => {
    // 动态路由不返回按钮
    if (isRoute && item.menu_type === 'F') return;
    if (isRoute) item = convertRouteParameter(item);
    map.set(item.menu_id, item);
  });

  map.forEach((item) => {
    const parent = map.get(item.parent_id);
    if (parent) (parent.children ?? (parent.children = [])).push(item);
    else if (item.parent_id === 0) result.push(item);
  });
  return result;
}

/**
 * 获取动态路由
 * @param {*} req
 * @param {*} res
 * @param {*} next
 */
async function getRouter(req, res, next) {
  try {
    let { user_id } = req.auth;
    const [user_role] = await poolPromise.execute(
      `select u_r.role_id,r.role_key from sys_user_role u_r left join sys_role r on r.role_id = u_r.role_id where user_id=?`,
      [user_id]
    );
    const roleIds = user_role.map((item) => item.role_id);
    const roleKeys = user_role.map((item) => item.role_key);

    let select_menu_sql = `select distinct m.*
    from sys_menu m
    left join sys_role_menu r_m on m.menu_id = r_m.menu_id
    left join sys_role r on r_m.role_id = r.role_id`;

    // 不是超级管理员，只能获取自己拥有的菜单
    if (!roleKeys.includes(config.SuperAdmin)) {
      select_menu_sql += ` where r.role_id in (${roleIds.join(',')})`;
    }
    const [list] = await poolPromise.execute(select_menu_sql);

    res.status(httpStatusCode.Ok).json({
      code: httpStatusCode.Ok,
      msg: '获取动态路由成功',
      data: treeMenu(list, true),
    });
  } catch (error) {
    next(error);
  }
}

/**
 * 获取菜单管理列表
 */
async function getMenuListTree(req, res, next) {
  try {
    const select_menu_sql = `select * from sys_menu`;
    const [list] = await poolPromise.execute(select_menu_sql);

    res.status(httpStatusCode.Ok).json({
      code: httpStatusCode.Ok,
      msg: '获取菜单列表成功',
      data: treeMenu(list),
    });
  } catch (error) {
    next(error);
  }
}

/**
 * 新增或更新菜单
 * @param {*} req
 * @param {*} res
 * @param {*} next
 */
async function insertOrUpdateMenu(req, res, next) {
  if (validateParams({ req, res, validationResult })) return;
  const connection = await poolPromise.getConnection(); // 获取一个连接对象
  try {
    await connection.beginTransaction(); // 开启事务
    const {
      menu_id = null,
      menu_name,
      parent_id = 0,
      route_name = null,
      path = null,
      component = null,
      target = null,
      menu_type,
      active_menu = null,
      icon = null,
      order_num = 0,
      is_link = 0,
      is_keep_alive = 0,
      is_hidden = 0,
      is_refresh = 0,
      is_affix = 0,
      is_full = 0,
      is_always_show = 0,
      perms = null,
      remark = null,
    } = req.body;
    const { user_id } = req.auth;
    const create_by = user_id;
    const update_by = user_id;

    const params = {
      menu_name,
      parent_id,
      route_name,
      path,
      component,
      target,
      menu_type,
      active_menu,
      icon,
      order_num,
      is_link,
      is_keep_alive,
      is_hidden,
      is_refresh,
      is_affix,
      is_full,
      is_always_show,
      perms,
      remark,
      create_by,
      update_by,
    };
    if (menu_id) {
      const update_menu_sql = `update sys_menu set ${Object.keys(params)
        .map((key) => `${key} = ?`)
        .join(',')} where menu_id = ?`;
      await connection.execute(update_menu_sql, [...Object.values(params), menu_id]);
    } else {
      const insert_menu_sql = `insert into sys_menu(${Object.keys(params).join(
        ','
      )}) values(${Object.keys(params)
        .map(() => '?')
        .join(',')})`;
      await connection.execute(insert_menu_sql, Object.values(params));
    }
    await connection.commit();
    res.status(httpStatusCode.Ok).json({
      code: httpStatusCode.Ok,
      msg: menu_id ? '修改菜单成功' : '添加菜单成功',
      data: null,
    });
  } catch (error) {
    await connection.rollback();
    next(error);
  } finally {
    connection.release();
  }
}

/**
 * 删除菜单
 * @param {*} req
 * @param {*} res
 * @param {*} next
 * @returns
 */
async function deleteMenu(req, res, next) {
  if (validateParams({ req, res, validationResult })) return;
  try {
    const { ids } = req.body;
    const delete_menu_sql = `delete from sys_menu where menu_id in (${new Array(ids.length)
      .fill('?')
      .join(',')})`;
    let [{ affectedRows: menu_affectedRows }] = await poolPromise.execute(delete_menu_sql, ids);
    if (!menu_affectedRows) {
      return res.status(httpStatusCode.InternalServerError).json({
        code: httpStatusCode.InternalServerError,
        msg: '删除菜单失败',
        data: null,
      });
    }
    res.status(httpStatusCode.Ok).json({
      code: httpStatusCode.Ok,
      msg: '删除菜单成功',
      data: null,
    });
  } catch (error) {
    next(error);
  }
}

module.exports = { getRouter, getMenuListTree, insertOrUpdateMenu, deleteMenu };
